﻿module app.exception;


import collie.utils.exception;
import std.json;
import std.exception;
import std.experimental.logger;
import std.json;
import std.net.curl : CurlException;
import hunt.http.exception;
import hunt.http.request;
import hunt.http.response;

enum ErrorCode:uint{
	AppIdNotFound = 400000,
	Argument=400001,
	Sign=400002,
	NotSupportChannel,
	OrderAlreadyPayed,
	EmptyRequest,
	WeixinPrepayError,
	Unknow = 800000
}

class ErroCodeExecption : Exception
{
	this(uint errocode,string msg, string file = __FILE__, size_t line = __LINE__,
		Throwable next = null) @nogc @safe pure nothrow
	{
		erroCode = errocode;
		super(msg, file, line, next);
	}
	
	uint erroCode;
}

mixin(buildErroCodeException!ErrorCode());
mixin ThrowExceptionBuild;

void runCatch(void delegate(Request) FUN,Request req)
{
	import std.json : JSONException;
	import std.exception;
	void sendErro(bool dofree = true)(Exception excep,uint errocode)
	{
		warning(excep.toString());
		
		JSONValue json;
		json["error_code"] = errocode;
		json["msg"] = excep.msg;
		collectException(req.createResponse.json(json.toString()).done());
		static if(dofree) {
			// NOTES: FREE the Exception
			import core.memory;
			excep.destroy;
			GC.free(cast(void *)excep);
		}
	}
	mixin(buildCatch!ErrorCode());
}

private:
string buildCatch(T)() if(is(T == enum))
{
	string str = "try{FUN(req);}\n";
	foreach(memberName; __traits(derivedMembers,T)){
		str ~= "catch(" ~ memberName  ~ "Exception  e){sendErro(e," ~ T.stringof ~ "." ~ memberName ~");}\n";
	}
	str ~= q{
		catch(ErroCodeExecption e){
			sendErro(e,e.erroCode);
		} catch (JSONException e){
			sendErro(e,ErrorCode.Argument);
		} 
		/*catch (DPQException e) {
		 sendErro(e,ErrorCode.HandleFailed);
		 import appd.model.db;
		 collieCathException!false(commitPG());
		 } */catch(CreateResponseException e){
			warning(e.toString());
			import core.memory;
			e.destroy;
			GC.free(cast(void *)e);
		}
		catch(Exception e){
			sendErro!false(e,ErrorCode.Unknow);
		} catch (Error e){
			import std.stdio;
			collieCathException!false({import std.experimental.logger; error(e.toString); writeln(e.toString());}());
			import core.stdc.stdlib;
			exit(-1);
		}
	};
	return str;
}